/** @file    Utilities.cpp
 *  @author  Alessandro Polo
 *  @version $Id: Utilities.cpp 2829 2010-08-02 20:45:47Z alex $
 *  @brief
 * File containing methods for the wosh::Utilities class.
 * The header for this class can be found in Utilities.h, check that file
 * for class description.
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

 #include <core/Utilities.h>

#ifdef WOSH_CORE_UTILS
 #include <core/utils/mtrand/mtrand.h>
 #include <core/utils/polarssl/polarssl_md5.h>
 #include <core/utils/polarssl/polarssl_sha2.h>
#endif

 #include <stdarg.h>
 #include <stdlib.h>
 #include <time.h>
 #include <fstream>
 #include <string.h>
 #include <string>
 #include <sstream>
 #include <algorithm> // std::transform (toupper, tolower)

#ifdef _OS_WINCE // WINCE doesn't support time()
 #include <core/wince/time_ce.h>
 #define time time_ce
 #define localtime localtime_ce
 #define strftime strftime_ce
 #define mktime mktime_ce
#else

 #ifdef _MSC_VER
  #define WIN32_VS
 #endif

#endif


using namespace std;
namespace wosh {

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////// MATH FUNCTIONS
#ifdef WOSH_CORE_UTILS
 unsigned long init[4] = {0x124, 0x234, 0x345, 0x456};
#else
 bool randInit = false;
#endif

int Utilities::randomInt() {
#ifdef WOSH_CORE_UTILS
//	static MTRand_int32 _randomInt_irand_static(init, 4); // 32-bit int generator
	static MTRand_int32 _randomInt_irand_static( std_time() ); // 32-bit int generator
	return _randomInt_irand_static();
#else
	if ( !randInit ) {
		srand( Utilities::std_time() );
		randInit = true;
	 }
	return rand();
#endif
 }

long Utilities::randomLong() {
#ifdef WOSH_CORE_UTILS
//	static MTRand_int32 _randomLong_irand_static(init, 4); // 32-bit int generator
	static MTRand_int32 _randomLong_irand_static( std_time() ); // 32-bit int generator
	return _randomLong_irand_static();
#else
	if ( !randInit ) {
		srand( Utilities::std_time() );
		randInit = true;
	 }
	return rand();
#endif
 }

int64 Utilities::randomInt64() {
	int64 hi = randomLong();
	long lo = randomLong();
	return ( hi << 32 ) + lo;
 }

double Utilities::randomDouble() {
#ifdef WOSH_CORE_UTILS
//	static MTRand _randomDouble_irand_static(init, 4);
	static MTRand _randomDouble_irand_static( std_time() );
	return _randomDouble_irand_static();
#else
	if ( !randInit ) {
		srand( Utilities::std_time() );
		randInit = true;
	 }
	return rand();
#endif
 }

int Utilities::randomInt( int min, int max_limit ) {
#ifdef WOSH_CORE_UTILS
	static MTRand _randomDouble_irand_static(init, 4); // 32-bit int generator
	return (int)((max_limit - min) * _randomDouble_irand_static()) + min;
#else
	if ( !randInit ) {
		srand( Utilities::std_time() );
		randInit = true;
	 }
	return rand();
#endif
 }

////////////////////////////////////////////////////////////////////////////////////////////// MATH FUNCTIONS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////// TIME FUNCTIONS

long Utilities::std_time() {
	return (long)time(NULL);
 }

int64 Utilities::std_time_ms() {
// #ifdef WIN32_VS
// 	FILETIME now;
// 	GetSystemTimeAsFileTime(&now);
// #else
	return (int64)time(NULL) * 1000;
// #endif
 }

void Utilities::getTimeStamp( char* buffer, int maxlen, const char* format, unsigned long epoch ) {
#ifdef _OS_WINCE
//time_t nowtime = epoch;
//string nowstr = asctime(localtime(&nowtime));
//nowstr.resize(nowstr.size() - 1);
//return nowstr;

#elif defined(WIN32_VS)
	struct tm timeinfo;
	time_t rawtime = epoch;
	localtime_s(&timeinfo, &rawtime );
	strftime(buffer,maxlen,format,&timeinfo);
#else
	struct tm * timeinfo;
	timeinfo = localtime( (const time_t*)&epoch );
	strftime(buffer,maxlen,format,timeinfo);
#endif
 }

std::string Utilities::getTimeStampUTF( unsigned long epoch ) {
	char buffer[80];
	memset(buffer, 0, 80);
	getTimeStampUTF(buffer, 80, epoch);
	return string(buffer);
 }

void Utilities::getTimeStampUTF( char* buffer, int maxlen, unsigned long epoch ) {
	getTimeStamp(buffer, maxlen, "%Y-%m-%d %H:%M:%S", epoch);
 }

unsigned long Utilities::parseTimeStampUTF( const std::string& utf_ts ) {
	struct tm dt; memset(&dt, 0, sizeof(tm)); int msec = 0;
	sscanf(utf_ts.c_str(), "%04d-%02d-%02d %02d:%02d:%02d:%03d", &dt.tm_year, &dt.tm_mon, &dt.tm_mday, &dt.tm_hour, &dt.tm_min, &dt.tm_sec, &msec);
	dt.tm_year -= 1900; dt.tm_mon -= 1;
//	unsigned long ti.tm_year, ti.tm_month, ti.tm_day, ti.tm_hour, ti.tm_min, ti.tm_second, msec; year = month = day = hour = min = second = msec = 0;
//	sscanf(utf_ts.c_str(), "%04d-%02d-%02d %02d:%02d:%02d", &year, &month, &day, &hour, &min, &second, &msec);
	return (unsigned long)mktime(&dt);
 }

std::string Utilities::getTimeSpan( int64 epoch_milliseconds ) {
	int64 seconds = epoch_milliseconds/1000;
	epoch_milliseconds = epoch_milliseconds%1000;
	unsigned long days = (unsigned long)(seconds/86400);
	seconds = seconds%86400;
	unsigned long hours = (unsigned long)(seconds/3600);
	seconds = seconds%3600;
	unsigned long mins = (unsigned long)(seconds/60);
	seconds = seconds%60;
	if ( days != 0 || hours != 0 )
		return Utilities::format("%ld:%ld:%ld:%ld:%ld", days,hours,mins,seconds,epoch_milliseconds );
	return Utilities::format("%ld:%ld:%ld", mins,seconds,epoch_milliseconds );
 }

int64 Utilities::parseTimeSpan( const std::string& timespan_millisec ) {
	unsigned long days, hours, mins, seconds, msec; days = hours = mins = seconds = msec = 0;
	if ( sscanf(timespan_millisec.c_str(), "%ld:%ld:%ld:%ld:%ld", &days, &hours, &mins, &seconds, &msec) < 4 ) {
		days = hours = mins = seconds = msec = 0;
		sscanf(timespan_millisec.c_str(), "%ld:%ld:%ld", &mins, &seconds, &msec);
	 }
	return (int64)(days*86400 + hours*3600 + mins*60 + seconds)*1000 + (int64)msec;
 }

////////////////////////////////////////////////////////////////////////////////////////////// TIME FUNCTIONS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////// STRING vs. VECTOR

std::string Utilities::joinVector( const std::vector<std::string>& str_vector, std::string sep, int offset ) {
	std::string res = "";
	std::vector<std::string>::const_iterator it;
	for ( it=str_vector.begin(); it!=str_vector.end(); ++it ) {
		if ( offset > 0 ) {
			--offset;
			continue;
		 }
		res += *it;
		if ( it < str_vector.end()-1 )
			res += sep;
	}
	return res;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
int Utilities::splitString(const std::string& input, char delimiter, std::vector<std::string>& results, bool includeEmpties)
 {
	int count = input.size();
	string token = "";
	int found = 0;
	for (int i=0; i<count; i++) {
		if ( input.at(i) == delimiter ) {
			if ( token.size() > 0 || includeEmpties ) {
				results.push_back(token);
				++found;
			 }
			token = "";
		 }
		token.append( 1, input.at(i) );
	 }

	if ( token.size() > 0 ) {
		results.push_back(token);
		++found;
	 }

	return found;
 }
*/
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

// original code by 'Paul J. Weiss' [http://www.codeproject.com/KB/string/stringsplit.aspx]
int Utilities::splitString(const std::string& input, const string& delimiter, std::vector<std::string>& results, bool includeEmpties, bool trimResult )
 {
	if ( input.empty() || delimiter.empty() ) return -1;
	int cPos = input.find(delimiter, 0);
    if( cPos == (int)std::string::npos ) {
		if ( (int)input.size() > 0 )
			results.push_back(input);
		return 1; 
	 }
	string buffer;
	cPos = 0;
    int cPosNext = -(int)delimiter.size();
	int numFound = 0;
	while (true){
		cPos = cPosNext + (int)delimiter.size();
		cPosNext = (int)input.find(delimiter, cPos);
		if ( cPosNext == 0 || cPos == cPosNext ) { // consecutive delimiters
			buffer = "";
		 }
		else if ( cPosNext == (int)std::string::npos || cPosNext <= cPos ) {
			buffer = input.substr(cPos);
		 }
		else  {
			buffer = input.substr(cPos, cPosNext-cPos);
		 }
		if ( trimResult )
			Utilities::trimSpaces(buffer);
		if ( buffer.size() > 0 || includeEmpties ) {
			results.push_back(buffer);
			++numFound;
		 }
		if ( cPosNext == (int)std::string::npos || cPosNext < cPos )
			break;
	}
    return numFound;
 }

/////////////////////////////////////////////////////////////////////////////////////////// STRING vs. VECTOR
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////// STRING MANIPULATION
//---------------------------------------------------------------------------
// credits http://www.xtremevbtalk.com/member.php?s=6d94525bb70d813486c5ac195c66a4b7&u=40423
short Utilities::isNumeric( const char* str )
{
	int len = strlen(str);	// get the length of string for iterations
	if ( len == 0 ) return 0;
	int i = -1;
	int deccnt = 0; // decimal counter
	while( ++i < len ) {
		if ( str[i] == '.' ) {
			if ( ++deccnt > 1 ) // is there a decimal
				return 0;  // too many decimals set return for not numeric
		 }
		else if ( isdigit(str[i]) == 0 )
			return 0;
	 }
	if ( deccnt != 0 ) {
		if ( deccnt == len )
			return 0;
		return 2; // double/decimal
	 }
	return 1; // 1 = integer/long
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// to be optimized!!
short Utilities::evalRegexWildChar( const std::string& str_regext, const std::string& str_data ) {
	if ( str_regext.at(0) == '*' && str_data.find(str_regext.substr(1)) == 1 )
		return 0;

	if ( str_regext.at(str_regext.size()-1) == '*' && str_data.find(str_regext.substr(0,str_regext.size()-2)) == 0 )
		return 0;

	return 1;
 }


//////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool Utilities::popWordFromString( std::string& strdata, std::string& word, const string& separator )
 {
	std::size_t pos = strdata.find(separator);
	if ( pos == std::string::npos ) {
		word = strdata;
		strdata = "";
		return false;
	 }

	word = strdata.substr(0, pos);
	strdata.erase(0, pos);
	return true;
 }

bool Utilities::extractWordFromString( const std::string& strdata, std::string& word, const string& separator )
 {
	std::size_t pos = strdata.find(separator);
	if ( pos == std::string::npos ) {
		word = strdata;
		return false;
	 }
	word = strdata.substr(0, pos);
	return true;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void Utilities::trimSpaces( std::string& str, short how )  
 {
	if ( how < 2 ) {
		int i = 0;
		while ( i < (int)str.size() && (str.at(i) == ' ' || str.at(i) == '\t') ) {
			str.erase(0,1);
		 }
	 }
	if ( how == 0 || how == 2  ) {
		int i = str.size()-1;
		while ( i > 0 && (str.at(i) == ' ' || str.at(i) == '\t') ) {
			str.erase(i);
			--i;
		 }
	 }
 }

void Utilities::trimEndLine( std::string& str, short how )  
 {
	if ( how < 2 ) {
		int i = 0;
		while ( i < (int)str.size() && (str.at(i) == '\n' || str.at(i) == '\r') ) {
			str.erase(0, i);
			++i;
		 }
	 }
	if ( how == 0 || how == 2  ) {
		int i = str.size()-1;
		while ( i > 0 && (str.at(i) == '\n' || str.at(i) == '\r') ) {
			str.erase(i);
			--i;
		 }
	 }
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void Utilities::toLower( std::string& str )
 {
	std::transform(str.begin(), str.end(), str.begin(), ::tolower);
 }

std::string Utilities::toLower( const std::string& str )
 {
	std::string temp = str;
	Utilities::toLower(temp);
	return temp;
 }

void Utilities::toUpper( std::string& str )
 {
	std::transform(str.begin(), str.end(), str.begin(), ::toupper);
 }

std::string Utilities::toUpper( const std::string& str )
 {
	std::string temp = str;
	Utilities::toUpper(temp);
	return temp;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

int Utilities::replace( std::string& input,  const std::string& find_me,  const std::string& replaced_with )
 {
	int i = 0;
	size_t pos = 0;
	while(true) {
		pos = input.find(find_me);
		if ( pos == string::npos  ) break;
		input.erase(pos, find_me.size());
		input.insert(pos, replaced_with);
		++i;
	 }
	return i;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

std::string Utilities::format( const char* format, ... )
 {
	///@bug ...sooo lame
	char* msgbuffer = new char[1023];
	memset(msgbuffer,'\0',1023);
	va_list list;
	va_start(list, format );
#ifdef _OS_WINCE
	vsprintf(msgbuffer,format, list);
#elif defined(WIN32_VS)
	vsprintf_s(msgbuffer, 1023, format, list);
#else
	vsprintf(msgbuffer,format, list);
#endif
	va_end(list);
	string temp(msgbuffer);
	delete [] msgbuffer;
	return temp;
 }

///////////////////////////////////////////////////////////////////////////////////////// STRING MANIPULATION
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////// STRING COMPARISON

int Utilities::compare_string_X( const std::string& str, const std::string& str2 )
 {
	std::string _str = str;
	Utilities::trimSpaces(_str);
	Utilities::toLower(_str);

	std::string _str2 = str2;
	Utilities::trimSpaces(_str2);
	Utilities::toLower(_str2);

	double temp = Utilities::levenshtein_distance(str, str2);
	if ( _str.size() == _str2.size() )
		temp /= _str.size() + _str2.size();
	else if ( _str.size() > _str2.size() )
		temp /= _str.size();
	else
		temp /= _str2.size();

	temp = 100 - (unsigned int)(temp * 100);
//	printf( "======>> %f: %s <=> %s \n", temp, _str.c_str(), _str2.c_str() );

	return (int)temp;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

//Levenshtein Distance Algorithm by Anders Sewerin Johansen
int Utilities::levenshtein_distance(const std::string source, const std::string target)
 {
	// Step 1
	const int n = source.length();
	const int m = target.length();
	if (n == 0)	return m;
	if (m == 0)	return n;

	// Good form to declare a TYPEDEF
	typedef std::vector< std::vector<int> > Tmatrix; 
	Tmatrix matrix(n+1);

	// Size the vectors in the 2.nd dimension. Unfortunately C++ doesn't
	// allow for allocation on declaration of 2.nd dimension of vec of vec
	for (int i = 0; i <= n; i++) {
		matrix[i].resize(m+1);
	 }

	// Step 2
	for (int i = 0; i <= n; i++) {
		matrix[i][0]=i;
	 }
	for (int j = 0; j <= m; j++) {
		matrix[0][j]=j;
	 }

	// Step 3
	for (int i = 1; i <= n; i++) {
		const char s_i = source[i-1];
		// Step 4
		for (int j = 1; j <= m; j++) {
			const char t_j = target[j-1];
			// Step 5
			int cost;
			if (s_i == t_j) {
				cost = 0;
			 }
			else {
				cost = 1;
			 }
			// Step 6
			const int above = matrix[i-1][j];
			const int left = matrix[i][j-1];
			const int diag = matrix[i-1][j-1];
			int cell = min( above + 1, min(left + 1, diag + cost));

			// Step 6A: Cover transposition, in addition to deletion,
			// insertion and substitution. This step is taken from:
			// Berghel, Hal ; Roach, David : "An Extension of Ukkonen's 
			// Enhanced Dynamic Programming ASM Algorithm"
			// (http://www.acm.org/~hlb/publications/asm/asm.html)

			if (i>2 && j>2) {
				int trans = matrix[i-2][j-2]+1;
				if ( source[i-2] != t_j ) trans++;
				if ( s_i != target[j-2] ) trans++;
				if  (cell > trans ) cell = trans;
			 }
			matrix[i][j]=cell;
		 }
	 }
	// Step 7
	return matrix[n][m];
}

/////////////////////////////////////////////////////////////////////////////////////////// STRING COMPARISON
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void Utilities::hex2string( string& hex_output, const char* hex_source, int size, const string& sep, unsigned short align )
 {
	if ( hex_source == NULL || size <= 0 ) return;
	std::ostringstream ss;
	for (int i=0; i<size; ++i) {
		if (i != 0)
			ss << sep;
		ss.width(align); //< Use two chars for each byte
		ss.fill('0'); //< Fill up with '0' if the number is only one hexadecimal digit
		ss << std::hex << (int)(hex_source[i]);
	 }
	hex_output = ss.str();
}

char* Utilities::string2hex( int& outputsize, const string& hex_input, unsigned int align, unsigned int sep_size )
 {
	// totsize = bytes * (align+sep_size) - sep_size
	if ( align+sep_size == 0 ) return NULL;
	outputsize = (hex_input.size()+sep_size) / (align+sep_size);
	char* data = new char[outputsize];
	memset(data, 0, outputsize);

	int outtmp;
	int j=0;
	for (int i=0; i<outputsize; ++i) {
		std::string s( "0x" + hex_input.substr(j,align));
		j += align + sep_size;
		std::istringstream iss(s);
		iss >> std::hex >> outtmp;
		data[i] = (char)outtmp;
	 }
	return data;
 }

////////////////////////////////////////////////////////////////////////////////////////// STRING CONVERSIONS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////// HASH FUNCTIONS
// General Purpose Hash Function Algorithms Library
// Author: Arash Partow - 2002
// URL: http://www.partow.net - http://www.partow.net/programming/hashfunctions/index.html 
 
unsigned int Utilities::hash_RS( const std::string& str )
 {
	unsigned int b    = 378551;
	unsigned int a    = 63689;
	unsigned int hash = 0;
	for(std::size_t i = 0; i < str.length(); i++) {
		hash = hash * a + str[i];
		a    = a * b;
	 }
	return hash;
 }

unsigned int Utilities::hash_JS( const std::string& str )
 {
	unsigned int hash = 1315423911;
	for(std::size_t i = 0; i < str.length(); i++) {
		hash ^= ((hash << 5) + str[i] + (hash >> 2));
	 }
	return hash;
 }

unsigned int Utilities::hash_PJW( const std::string& str )
 {
	unsigned int BitsInUnsignedInt = (unsigned int)(sizeof(unsigned int) * 8);
	unsigned int ThreeQuarters     = (unsigned int)((BitsInUnsignedInt  * 3) / 4);
	unsigned int OneEighth         = (unsigned int)(BitsInUnsignedInt / 8);
	unsigned int HighBits          = (unsigned int)(0xFFFFFFFF) << (BitsInUnsignedInt - OneEighth);
	unsigned int hash              = 0;
	unsigned int test              = 0;

	for(std::size_t i = 0; i < str.length(); i++) {
		hash = (hash << OneEighth) + str[i];
		if( (test = hash & HighBits)  != 0 ) {
			hash = (( hash ^ (test >> ThreeQuarters)) & (~HighBits));
		 }
	 }
	return hash;
}

unsigned int Utilities::hash_ELF( const std::string& str )
 {
	unsigned int hash = 0;
	unsigned int x    = 0;
	for(std::size_t i = 0; i < str.length(); i++) {
		hash = (hash << 4) + str[i];
		if( (x = hash & 0xF0000000L) != 0 ) {
			hash ^= (x >> 24);
		 }
		hash &= ~x;
	 }
	return hash;
 }

unsigned int Utilities::hash_BKDR( const std::string& str )
 {
	unsigned int seed = 131; // 31 131 1313 13131 131313 etc..
	unsigned int hash = 0;
	for(std::size_t i = 0; i < str.length(); i++) {
		hash = (hash * seed) + str[i];
	 }
	return hash;
 }

unsigned int Utilities::hash_SDBM( const std::string& str )
 {
	unsigned int hash = 0;
	for(std::size_t i = 0; i < str.length(); i++) {
		hash = str[i] + (hash << 6) + (hash << 16) - hash;
	 }
	return hash;
 }

unsigned int Utilities::hash_DJB( const std::string& str )
 {
	unsigned int hash = 5381;
	for(std::size_t i = 0; i < str.length(); i++) {
		hash = ((hash << 5) + hash) + str[i];
	 }
	return hash;
 }

unsigned int Utilities::hash_DEK( const std::string& str )
 {
	unsigned int hash = static_cast<unsigned int>(str.length());
	for(std::size_t i = 0; i < str.length(); i++) {
		hash = ((hash << 5) ^ (hash >> 27)) ^ str[i];
	 }
	return hash;
 }

unsigned int Utilities::hash_BP( const std::string& str )
 {
	unsigned int hash = 0;
	for(std::size_t i = 0; i < str.length(); i++) {
		hash = hash << 7 ^ str[i];
	 }
	return hash;
 }

unsigned int Utilities::hash_FNV( const std::string& str )
 {
	const unsigned int fnv_prime = 0x811C9DC5;
	unsigned int hash = 0;
	for(std::size_t i = 0; i < str.length(); i++) {
		hash *= fnv_prime;
		hash ^= str[i];
	 }
	return hash;
}

unsigned int Utilities::hash_AP( const std::string& str )
 {
	unsigned int hash = 0xAAAAAAAA;
	for(std::size_t i = 0; i < str.length(); i++) {
		hash ^= ((i & 1) == 0) ? (  (hash <<  7) ^ str[i] * (hash >> 3)) :
								(~((hash << 11) + str[i] ^ (hash >> 5)));
	 }
	return hash;
 }

////////////////////////////////////////////////////////////////////////////////////////////// HASH FUNCTIONS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////// MD5 FUNCTIONS

bool Utilities::calculateMD5( std::string& md5str, const char* format, ... )
 {
	///@bug ...sooo lame
	char* msgbuffer = new char[1023+1];
	memset(msgbuffer,'\0',1023+1);
	va_list list;
	va_start(list, format );
#ifdef _OS_WINCE
	vsprintf(msgbuffer,format, list);
#elif defined(WIN32_VS)
	vsprintf_s(msgbuffer, 1023, format, list);
#else
	vsprintf(msgbuffer,format, list);
#endif
	va_end(list);

	unsigned char digest[16];
	memset(digest,'\0',16);
	md5( (unsigned char*) msgbuffer, 13, digest );
	md5str.assign( (char*)digest );

	//printf( "\n  MD5('%s') = ", msgbuffer );
	//for( i = 0; i < 16; i++ )
	//	printf( "%02x", digest[i] );

	return true;
 }

bool Utilities::calculateMD5( const std::string& data, std::string& md5str )
 {
#ifdef WOSH_CORE_UTILS
	unsigned char digest[16];
	memset(digest,'\0',16);
	md5( (unsigned char*) data.c_str(), data.size(), digest );
	md5str.assign( (char*)digest );
	return true;
#else
	return false;
#endif
 }

void Utilities::UUID( std::string& uuid_str ) {

unsigned int v1 = Utilities::randomLong();
int v2 = Utilities::randomLong();
unsigned int v3 = Utilities::randomLong();
unsigned int v4 = Utilities::randomLong();
char guid_c_str[37];
sprintf(guid_c_str, "%08X-%04hX-%06X-%02X", v1, v2, v3, v4 );
uuid_str = guid_c_str;
/*
	unsigned char digest[32];
	memset(digest,'\0',32);
	sha2_context context;
	sha2_starts( &context, 0 );
	int64 value = Utilities::randomLong();// << Utilities::randomLong();
 	sha2_update( &context, (const unsigned char*)&value, sizeof(int64) );
//	printf("UUID");
	sha2_finish( &context, digest );
	uuid_str.assign( (char*)digest );
//	 Utilities::calculateMD5( Utilities::toString<long>(Utilities::randomLong()), uuid_str );
*/

 }

/////////////////////////////////////////////////////////////////////////////////////////////// MD5 FUNCTIONS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////


}; // namespace wosh
